package com.xxl.job.admin.core.thread;

import com.xxl.job.core.Constant;
import com.xxl.job.core.enums.RegistTypeEnum;

import lombok.extern.slf4j.Slf4j;

import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.core.model.XxlJobRegistry;
import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
 * 自动注册执行节点的执行器，维护可用执行点守护进程
 * 		删除掉过期Job执行点， xxl_job_qrtz_trigger_registry -  XxlJobRegistry
 * 		将可用的执行点数据，更新到	xxl_job_qrtz_trigger_group  -  XxlJobGroup.address_list
 * 
 * job registry instance
 * @author xuxueli 2016-10-02 19:10:24
 */
@Slf4j
public class JobRegistryMonitorHelper {
	private static JobRegistryMonitorHelper instance = new JobRegistryMonitorHelper();
	public static JobRegistryMonitorHelper getInstance(){
		return instance;
	}

	
	private Thread registryThread;
	private volatile boolean toStop = false;
	
	public void start() {
		
		registryThread = new Thread(new Runnable() {
			@Override
			public void run() {
				while (!toStop) {
					try {
						log.info("维护可用执行点注册信息守护线程 {} : s一次",Constant.BEAT_TIMEOUT);
						
						// auto registry group 找到需要自动注册的执行器
						List<XxlJobGroup> xxlJobGroups = XxlJobDynamicScheduler.xxlJobGroupDao.findByAddressType(0);
						if (CollectionUtils.isNotEmpty(xxlJobGroups)) {

							// remove dead address (admin/executor) 移除超时的执行点
							XxlJobDynamicScheduler.xxlJobRegistryDao.removeDead(Constant.DEAD_TIMEOUT);

							// fresh online address (admin/executor)
							Map<String, List<String>> appAddressMap = new HashMap<String, List<String>>();
							
							//找到未超时的可用执行点
							List<XxlJobRegistry> xxlJobRegistrys = XxlJobDynamicScheduler.xxlJobRegistryDao.findAll(Constant.DEAD_TIMEOUT);
							if (xxlJobRegistrys != null) {
								for (XxlJobRegistry xxlJobRegistry: xxlJobRegistrys) {
									if (RegistTypeEnum.EXECUTOR.name().equals(xxlJobRegistry.getRegistryGroup())) {
										String appName = xxlJobRegistry.getRegistryKey();
										List<String> registryList = appAddressMap.get(appName);
										if (registryList == null) {
											registryList = new ArrayList<String>();
										}

										if (!registryList.contains(xxlJobRegistry.getRegistryValue())) {
											registryList.add(xxlJobRegistry.getRegistryValue());
										}
										appAddressMap.put(appName, registryList);
									}
								}
							}

							// fresh group address, 刷新在线执行点列表，xxl_job_qrtz_trigger_group刷新表
							for (XxlJobGroup xxlJobGroup: xxlJobGroups) {
								List<String> registryList = appAddressMap.get(xxlJobGroup.getAppName());
								String addressListStr = null;
								if (CollectionUtils.isNotEmpty(registryList)) {
									Collections.sort(registryList);
									addressListStr = StringUtils.join(registryList, ",");
								}
								xxlJobGroup.setAddressList(addressListStr);
								XxlJobDynamicScheduler.xxlJobGroupDao.update(xxlJobGroup);
							}
						}
						
					} catch (Exception e) {
						log.error("job registry instance error:{}", e);
					}
					
					
					try {
						TimeUnit.SECONDS.sleep(Constant.BEAT_TIMEOUT);
					} catch (InterruptedException e) {
						log.error("job registry instance error:{}", e);
					}
				}
			}
		});
		registryThread.setDaemon(true);
		registryThread.start();
	}

	public void toStop(){
		toStop = true;
		
		//interrupt and wait
		registryThread.interrupt();
		try {
			registryThread.join();
		}
		catch (InterruptedException e) {
			log.error(e.getMessage(), e);
		}
		
	}
	
}